﻿using System;
using System.Collections;
using System.IO;
using System.Reflection;
using Automator.Tasks.Core;

namespace Automator.Runtime
{
    /// <summary>
    /// Static class that implements dynamic load of the Tasks, main part of the Automator extensibility
    /// </summary>
    public static class TaskManager
    {
        /// <summary>
        /// Gets instances of all types derived from Task that are stored in a given assembly
        /// </summary>
        /// <param name="assembly">Loaded assembly</param>
        /// <param name="collection">Reference to a collection, to which Tasks should be added</param>
        public static void GetAllTasksFromAssembly(Assembly assembly, ref TaskCollection collection)
        {
            IEnumerator enumerator = assembly.GetExportedTypes().GetEnumerator();
            enumerator.Reset();
            while (enumerator.MoveNext())
            {
                Type curType = (Type)enumerator.Current;
                if (curType.BaseType.Equals(typeof(Task)))
                {
                    //looking for base constructor without parameters
                    ConstructorInfo constructor = curType.GetConstructor(new Type[] { });
                    if (constructor != null && constructor.IsPublic)
                    {
                        Task task = (Task)constructor.Invoke(new object[] { });
                        collection.Add(task);
                    }
                }
            }
        }

        /// <summary>
        /// Gets instances of all types derived from Task that are stored in a given assembly
        /// </summary>
        /// <param name="assemblyPath">Full path to assembly file</param>
        /// <param name="collection">Reference to a collection, to which Tasks should be added</param>
        public static void GetAllTasksFromAssembly(string assemblyPath, ref TaskCollection collection)
        {
            if (File.Exists(assemblyPath))
            {
                GetAllTasksFromAssembly(Assembly.LoadFrom(assemblyPath), ref collection);
            }
        }

        /// <summary>
        /// Gets an instance of the given Task type
        /// </summary>
        /// <param name="taskType">Assembly-qualified name of the type</param>
        /// <returns></returns>
        public static Task GetTaskFromAssemblyQualifiedName(string taskType)
        {
            Task result = null;

            Type type = Type.GetType(taskType, AddinResolver, null, true);
            if (type != null)
            {
                //looking for base constructor without parameters
                ConstructorInfo constructor = type.GetConstructor(new Type[] { });
                if (constructor != null && constructor.IsPublic)
                    result = (Task)constructor.Invoke(new object[] { });                
            }
            
            return result;
        }
        
        private static Assembly AddinResolver(AssemblyName source)
        {
            string filename = String.Format("{0}.dll", source.Name);
            if (File.Exists(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, filename)))
                return Assembly.Load(source);
            else
                return Assembly.LoadFile(Path.Combine(Automator.Runtime.Environment.addinsDir, filename));
        }
    }
}
